package com.molichuxing.framework.utils;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Random;

/**
 * 图片验证码工具类
 */
public class GraphValidateCode {

	/**
	 * 随机产生只有数字的字符串 private String
	 */
	private String randString = "0123456789";

	/**
	 * 图片宽
	 */
	private int width = 70;

	/**
	 * 图片高
	 */

	private int height = 25;

	/**
	 * 干扰线数量
	 */
	private int lineSize = 5;

	/**
	 * 随机产生字符数量
	 */
	private int stringNum = 4;

	private static final Logger logger = LoggerFactory.getLogger(GraphValidateCode.class);

	private Random random = new Random();

	/**
	 * 字符串结果
	 */
	private String code;

	/**
	 * 获得字体
	 */
	private Font getFont() {
		return new Font("Fixedsys", Font.CENTER_BASELINE, 18);
	}

	/**
	 * 获得颜色
	 */
	private Color getRandColor(int fc, int bc) {

		int maxValue = 255;

		if (fc > maxValue) {
			fc = 255;
		}

		if (bc > maxValue) {
			bc = 255;
		}

		int r = fc + random.nextInt(bc - fc - 16);
		int g = fc + random.nextInt(bc - fc - 14);
		int b = fc + random.nextInt(bc - fc - 18);
		return new Color(r, g, b);
	}

	/**
	 * 生成随机图片
	 *
	 * @return BufferedImage rand code pic
	 */
	public BufferedImage getRandCodePic() {

		// BufferedImage类是具有缓冲区的Image类,Image类是用于描述图像信息的类
		BufferedImage image = new BufferedImage(this.getWidth(), this.getHeight(), BufferedImage.TYPE_INT_BGR);

		// 产生Image对象的Graphics对象,改对象可以在图像上进行各种绘制操作
		Graphics g = image.getGraphics();

		// 图片大小
		g.fillRect(0, 0, this.getWidth(), this.getHeight());

		// 字体大小
		// g.setFont(new Font("Times New Roman", Font.ROMAN_BASELINE, 18));

		g.setColor(getRandColor(110, 133));

		logger.info("设置字体颜色");

		// 绘制随机字符
		String randomString = "";
		for (int i = 1; i <= this.getStringNum(); i++) {
			randomString = drawString(g, randomString, i);
		}

		// 绘制干扰线
		for (int i = 0; i <= this.lineSize; i++) {
			drawLine(g);
		}

		logger.info(randomString);

		this.setCode(randomString);
		g.dispose();

		return image;
	}

	/**
	 * 绘制字符串
	 */
	private String drawString(Graphics g, String randomString, int i) {
		g.setFont(getFont());
		g.setColor(new Color(random.nextInt(101), random.nextInt(111), random.nextInt(121)));
		String rand = String.valueOf(getRandomString(random.nextInt(randString.length())));
		randomString += rand;

		logger.info("绘制随机字符={}", rand);

		g.translate(random.nextInt(3), random.nextInt(3));

		g.drawString(rand, 13 * i, 16);
		return randomString;
	}

	/**
	 * 绘制干扰线
	 */
	private void drawLine(Graphics g) {
		int x = random.nextInt(this.getWidth());
		int y = random.nextInt(this.getHeight());
		int xl = random.nextInt(13);
		int yl = random.nextInt(15);
		g.drawLine(x, y, x + xl, y + yl);
	}

	/**
	 * 获取随机的字符
	 *
	 * @param num
	 *            the num
	 * @return the random string
	 */
	public String getRandomString(int num) {
		return String.valueOf(randString.charAt(num));
	}

	/**
	 * 图片转换二进制
	 * 
	 * @param codePic
	 * @return
	 * @throws IOException
	 */
	public String getImageBinary(BufferedImage codePic) throws IOException {
		ByteArrayOutputStream baos = new ByteArrayOutputStream();

		//经测试转换的图片是格式这里就什么格式，否则会失真
		ImageIO.write(codePic, "jpg", baos);

		byte[] bytes = baos.toByteArray();
		return java.util.Base64.getEncoder().encodeToString(bytes);
	}

	/**
	 * Gets width.
	 *
	 * @return the width
	 */
	public int getWidth() {
		return width;
	}

	/**
	 * Sets width.
	 *
	 * @param width
	 *            the width
	 */
	public void setWidth(int width) {
		this.width = width;
	}

	/**
	 * Gets height.
	 *
	 * @return the height
	 */
	public int getHeight() {
		return height;
	}

	/**
	 * Sets height.
	 *
	 * @param height
	 *            the height
	 */
	public void setHeight(int height) {
		this.height = height;
	}

	/**
	 * Gets line size.
	 *
	 * @return the line size
	 */
	public int getLineSize() {
		return lineSize;
	}

	/**
	 * Sets line size.
	 *
	 * @param lineSize
	 *            the line size
	 */
	public void setLineSize(int lineSize) {
		this.lineSize = lineSize;
	}

	/**
	 * Gets string num.
	 *
	 * @return the string num
	 */
	public int getStringNum() {
		return stringNum;
	}

	/**
	 * Sets string num.
	 *
	 * @param stringNum
	 *            the string num
	 */
	public void setStringNum(int stringNum) {
		this.stringNum = stringNum;
	}

	/**
	 * Gets code.
	 *
	 * @return the code
	 */
	public String getCode() {
		return code;
	}

	/**
	 * Sets code.
	 *
	 * @param code
	 *            the code
	 */
	public void setCode(String code) {
		this.code = code;
	}
}
